/******************************************************************************\
    LanguageDataBase.h discribes a database of languages.
    It's used with acm server. See main.cpp for details.
    Copyright (C) 2008  Victor Vinogradov (fly3333@gmail.com)

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
\******************************************************************************/

#pragma once

#include ".\BaseDataBase.hpp"

namespace nsLanguageDataBase
{
	const size_t MAX_TITLE_LENGTH = 255;

	struct sLanguageData0
	{
		unsigned long Key;
		unsigned long PluginId;
		unsigned long Index;
		char Title[ MAX_TITLE_LENGTH + 1 ];
	};

	struct sLanguageData1
	{
		unsigned long Key;
		unsigned long PluginId;
		unsigned long Index;
		char Title[ MAX_TITLE_LENGTH + 1 ];
	};

	typedef sLanguageData1 sLanguageData;

	void ConversionFunction0( void *new_data, const void *prev_data );

	const sConversionTable ConversionTable[] =
	{
		{ sizeof( sLanguageData0 ), sizeof( sLanguageData1 ), &ConversionFunction0 }
	};

	struct PluginIdCompare : public std::binary_function< cDataPointer< sLanguageData >, cDataPointer< sLanguageData >, bool >
	{
		bool operator()( const cDataPointer< sLanguageData > &left, const cDataPointer< sLanguageData > &right ) const
		{
			return left->PluginId < right->PluginId ||
				left->PluginId == right->PluginId && left->Index < right->Index;
		}
	};

	typedef cBaseDataBase< sLanguageData >::KeyIterator KeyIterator;
	typedef cPublicIterator< sLanguageData, PluginIdCompare > PluginIdIterator;

	class cWardLanguageDataBase : public cBaseDataBase< sLanguageData >
	{
	private:
		std::set< cDataPointer< sLanguageData >, PluginIdCompare > PluginIdIndex;
	protected:
		virtual bool Indexed( const cDataPointer< sLanguageData > &data_pointer )
		{
			return PluginIdIndex.find( data_pointer ) != PluginIdIndex.end();
		}
		virtual void InsertIndex( const cDataPointer< sLanguageData > &data_pointer )
		{
			PluginIdIndex.insert( data_pointer );
		}
		virtual void UpdateIndex( const cDataPointer< sLanguageData > &data_pointer, unsigned long index )
		{
			PluginIdIndex.find( data_pointer )->Index = index;
		}
		virtual void DeleteIndex( const cDataPointer< sLanguageData > &data_pointer )
		{
			PluginIdIndex.erase( data_pointer );
		}
		virtual void ClearIndex()
		{
			PluginIdIndex.clear();
		}
	public:
		cWardLanguageDataBase( /*bool auto_update*/ )
			: cBaseDataBase( /*auto_update*/ )
		{
		}
		PluginIdIterator BeginByPluginId() const
		{
			return PluginIdIterator( PluginIdIndex.begin() );
		}
		PluginIdIterator LowerBoundByPluginId( unsigned long plugin_id ) const
		{
			sLanguageData language_data;
			language_data.PluginId = plugin_id;
			language_data.Index = 0;
			return PluginIdIterator( PluginIdIndex.lower_bound( cDataPointer< sLanguageData >( &language_data ) ) );
		}
		PluginIdIterator UpperBoundByPluginId( unsigned long plugin_id ) const
		{
			sLanguageData language_data;
			language_data.PluginId = plugin_id;
			language_data.Index = 0xfffffffful;
			return PluginIdIterator( PluginIdIndex.upper_bound( cDataPointer< sLanguageData >( &language_data ) ) );
		}
		PluginIdIterator FindByPluginIdAndIndex( unsigned long plugin_id, unsigned long index )
		{
			sLanguageData language_data;
			language_data.PluginId = plugin_id;
			language_data.Index = index;
			return PluginIdIterator( PluginIdIndex.find( cDataPointer< sLanguageData >( &language_data ) ) );
		}
		PluginIdIterator EndByPluginId() const
		{
			return PluginIdIterator( PluginIdIndex.end() );
		}
		bool GetByPluginIdAndIndex( unsigned long plugin_id, unsigned long index, sLanguageData &language_data )
		{
			cLocker locker( *this );
			PluginIdIterator iterator = FindByPluginIdAndIndex( plugin_id, index );
			if( iterator == EndByPluginId() )
				return false;
			language_data = *iterator;
			return true;
		}
	};

	class cLanguageDataBase : public cPointerObject< cWardLanguageDataBase >
	{
	public:
		bool Create( /*bool auto_update = false*/ )
		{
			cWardLanguageDataBase *ward_language_data_base;
			try
			{
				ward_language_data_base = new cWardLanguageDataBase( /*auto_update*/ );
			}
			catch( ... )
			{
				return false;
			}
			if( !SwitchToWardObject( ward_language_data_base ) )
			{
				delete ward_language_data_base;
				return false;
			}
			return true;
		}
		void Destroy()
		{
			SwitchToSubObject( NULL );
		}
	};
}
